package net.flashpunk.graphics 
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.utils.Dictionary;
	import net.flashpunk.FP;
	import net.flashpunk.Graphic;
	
	/**
	 * Creates a pre-rotated Image strip to increase runtime performance for rotating graphics.
	 */
	public class PreRotation extends Image
	{
		/**
		 * Current angle to fetch the pre-rotated frame from.
		 */
		public var frameAngle:Number = 0;
		
		/**
		 * Constructor.
		 * @param	source			The source image to be rotated.
		 * @param	frameCount		How many frames to use. More frames result in smoother rotations.
		 * @param	smooth			Make the rotated graphic appear less pixelly.
		 */
		public function PreRotation(source:Class, frameCount:uint = 36, smooth:Boolean = false) 
		{
			var r:BitmapData = _rotated[source];
			_frame = new Rectangle(0, 0, _size[source], _size[source]);
			if (!r)
			{
				// produce a rotated bitmap strip
				var temp:BitmapData = (new source).bitmapData,
					size:uint = _size[source] = Math.ceil(FP.distance(0, 0, temp.width, temp.height));
				_frame.width = _frame.height = size;
				var width:uint = _frame.width * frameCount,
					height:uint = _frame.height;
				if (width > _MAX_WIDTH)
				{
					width = _MAX_WIDTH - (_MAX_WIDTH % _frame.width);
					height = Math.ceil(frameCount / (width / _frame.width)) * _frame.height;
				}
				r = new BitmapData(width, height, true, 0);
				var m:Matrix = FP.matrix,
					a:Number = 0,
					aa:Number = (Math.PI * 2) / -frameCount,
					ox:uint = temp.width / 2,
					oy:uint = temp.height / 2,
					o:uint = _frame.width / 2,
					x:uint = 0,
					y:uint = 0;
				while (y < height)
				{
					while (x < width)
					{
						m.identity();
						m.translate(-ox, -oy);
						m.rotate(a);
						m.translate(o + x, o + y);
						r.draw(temp, m, null, null, null, smooth);
						x += _frame.width;
						a += aa;
					}
					x = 0;
					y += _frame.height;
				}
			}
			_source = r;
			_width = r.width;
			_frameCount = frameCount;
			super(_source, _frame);
		}
		
		/** @private Renders the PreRotated graphic. */
		override public function render(point:Point, camera:Point):void 
		{
			frameAngle %= 360;
			if (frameAngle < 0) frameAngle += 360;
			_current = uint(_frameCount * (frameAngle / 360));
			if (_last != _current)
			{
				_last = _current;
				_frame.x = _frame.width * _last;
				_frame.y = uint(_frame.x / _width) * _frame.height;
				_frame.x %= _width;
				updateBuffer();
			}
			super.render(point, camera);
		}
		
		// Rotation information.
		/** @private */ private var _width:uint;
		/** @private */ private var _frame:Rectangle;
		/** @private */ private var _frameCount:uint;
		/** @private */ private var _last:int = -1;
		/** @private */ private var _current:int = -1;
		
		// Global information.
		/** @private */ private static var _rotated:Dictionary = new Dictionary;
		/** @private */ private static var _size:Dictionary = new Dictionary;
		/** @private */ private static const _MAX_WIDTH:uint = 4000;
		/** @private */ private static const _MAX_HEIGHT:uint = 4000;
	}
}